package com.think.cloud.thinkshop.mall.service.memberuser.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.think.cloud.thinkshop.common.enums.RabbitMessageTypeEnum;
import com.think.cloud.thinkshop.mall.controller.admin.memberuser.dto.MemberGroupUserTraitDetailDTO;
import com.think.cloud.thinkshop.mall.controller.admin.memberuser.dto.MemberTagRefDTO;
import com.think.cloud.thinkshop.mall.controller.admin.memberuser.vo.*;
import com.think.cloud.thinkshop.mall.convert.memberuser.MemberGroupConvert;
import com.think.cloud.thinkshop.mall.domain.memberuser.MemberGroup;
import com.think.cloud.thinkshop.mall.domain.memberuser.MemberGroupRef;
import com.think.cloud.thinkshop.mall.domain.memberuser.MemberTag;
import com.think.cloud.thinkshop.mall.domain.memberuser.MemberUser;
import com.think.cloud.thinkshop.mall.enums.member.MemberGroupTraitConditionEnum;
import com.think.cloud.thinkshop.mall.enums.member.MemberGroupTraitEnum;
import com.think.cloud.thinkshop.mall.mapper.memberuser.MemberGroupMapper;
import com.think.cloud.thinkshop.mall.mapper.memberuser.MemberGroupRefMapper;
import com.think.cloud.thinkshop.mall.rabbit.producer.MessageProducer;
import com.think.cloud.thinkshop.mall.service.memberuser.IMemberGroupService;
import com.think.cloud.thinkshop.mall.service.memberuser.IMemberOperationPlanService;
import com.think.cloud.thinkshop.mall.service.memberuser.IMemberTagRefService;
import com.think.cloud.thinkshop.mall.service.memberuser.IMemberUserService;
import com.think.common.core.exception.ServiceException;
import com.think.common.core.utils.PageUtils;
import com.think.common.core.web.page.TableDataInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * 客户分群Service业务层处理
 *
 * @author guangxian
 * @date 2024-06-03
 */
@Slf4j
@Service
public class MemberGroupServiceImpl implements IMemberGroupService {
    @Autowired
    private MemberGroupMapper memberGroupMapper;
    @Autowired
    private MemberGroupRefMapper memberGroupRefMapper;
    @Autowired
    private MessageProducer messageProducer;
    @Autowired
    private IMemberUserService memberUserService;
    @Autowired
    private IMemberTagRefService memberTagRefService;
    @Autowired
    @Lazy
    private IMemberOperationPlanService memberOperationPlanService;
    private final Lock lock = new ReentrantLock();


    /**
     * 查询客户分群
     *
     * @param id 客户分群主键
     * @return 客户分群
     */
    @Override
    public MemberGroupDetailRespVO selectMemberGroupById(Long id) {
        return MemberGroupConvert.INSTANCE.convert(memberGroupMapper.selectById(id));
    }

    @Override
    public List<MemberGroupDetailRespVO> selectMemberGroupById(List<Long> id) {
        return MemberGroupConvert.INSTANCE.convertList(
                memberGroupMapper.selectList(
                        Wrappers.<MemberGroup>lambdaQuery().in(MemberGroup::getId, id)
                )
        );
    }

    /**
     * 查询客户分群列表
     *
     * @param vo 客户分群查询参数
     * @return 客户分群
     */
    @Override
    public List<MemberGroup> selectMemberGroupList(MemberGroupReqVO vo) {
        return memberGroupMapper.selectList(Wrappers.<MemberGroup>lambdaQuery()
                .eq(ObjectUtil.isNotNull(vo.getName()), MemberGroup::getName, vo.getName())
                .ge(ObjectUtil.isNotNull(vo.getUserCountMin()), MemberGroup::getUserCount, vo.getUserCountMin())
                .le(ObjectUtil.isNotNull(vo.getUserCountMax()), MemberGroup::getUserCount, vo.getUserCountMax())
        );
    }

    /**
     * 用于新增、编辑用户分区的特征列表
     *
     * @return
     */
    @Override
    public List<MemberGroupEditTraitRespVO> getTraitOption() {
        return memberGroupMapper.getTraitList();
    }

    /**
     * 新增客户分群
     *
     * @param vo 客户分群
     * @return 结果
     */
    @Override
    public int insertMemberGroup(MemberGroupAddReqVO vo) {
        String groupName = vo.getName();
        judgmentGroupNameExist(groupName, null);
        int i = memberGroupMapper.insert(MemberGroupConvert.INSTANCE.convert(vo));
        if (i > 0) {
            messageProducer.sendMessage(groupName, RabbitMessageTypeEnum.MEMBER_GROUP_CONFIG_INSERT_OR_UPDATE);
        }
        return i;
    }

    /**
     * 修改客户分群
     *
     * @param vo 客户分群
     * @return 结果
     */
    @Override
    public int updateMemberGroup(MemberGroupAddReqVO vo) {
        Long id = vo.getId();
        if (id == null) {
            throw new ServiceException("编辑用户组id不能为空");
        }
        String groupName = vo.getName();
        judgmentGroupNameExist(groupName, id);
        int i = memberGroupMapper.updateById(MemberGroupConvert.INSTANCE.convert(vo));
        if (i > 0) {
            messageProducer.sendMessage(groupName, RabbitMessageTypeEnum.MEMBER_GROUP_CONFIG_INSERT_OR_UPDATE);
        }
        return i;
    }

    /**
     * 判断组名是否存在
     *
     * @param groupName 组名
     * @param id
     */
    private void judgmentGroupNameExist(String groupName, Long id) {
        MemberGroup memberGroup = memberGroupMapper.selectOne(Wrappers.<MemberGroup>lambdaQuery()
                .eq(MemberGroup::getName, groupName)
                .ne(id != null, MemberGroup::getId, id)
        );
        if (memberGroup != null) {
            throw new ServiceException("该组名已存在");
        }
    }

    /**
     * 批量删除客户分群信息
     *
     * @param id 主键集合
     * @return 结果
     */
    @Override
    public int deleteById(Long id) {
        return memberGroupMapper.deleteById(id);
    }

    /**
     * 批量删除客户分群信息
     *
     * @param ids 主键集合
     * @return 结果
     */
    @Override
    public int batchDelete(List<Long> ids) {
        return memberGroupMapper.deleteBatchIds(ids);
    }

    @Override
    public List<Long> selectUseridListByGroupIds(List<Long> groupIdList) {
        return memberGroupMapper.selectUseridListByGroupIds(groupIdList);
    }

    /**
     * 查看组中客户详情
     *
     * @param groupId
     */
    @Override
    public TableDataInfo memberGroupDetail(Long groupId) {
        List<MemberGroupUserRespVO> result = new ArrayList<>();
        List<MemberGroupRef> memberGroupRefs = memberGroupRefMapper.selectList(
                Wrappers.<MemberGroupRef>lambdaQuery()
                .eq(MemberGroupRef::getMemberGroupId, groupId)
        );
        for (MemberGroupRef memberGroupRef : memberGroupRefs) {
            Long userId = memberGroupRef.getUserId();
            MemberGroupUserRespVO item = new MemberGroupUserRespVO();
            MemberUser user = memberUserService.selectMemberUserById(userId);
            item.setId(user.getId());
            item.setLastName(user.getLastName());
            item.setFirstName(user.getFirstName());
            item.setEmail(user.getEmail());
            item.setCreateTime(new Timestamp(user.getCreateTime().getTime()));
            item.setOrderCount(user.getOrderCount());
            item.setLastConsumeTime(user.getLastConsumeTime());
            item.setTotalOrderAmount(user.getTotalOrderAmount());
            //  填充查询 : 标签
            item.setTags(
                    memberTagRefService.selectByUserIds(Collections.singletonList(userId))
                            .stream().map(MemberTagRefDTO::getTagName).collect(Collectors.toList())
            );
            result.add(item);
        }
        return new TableDataInfo(result, PageUtils.getTotal(memberGroupRefs));
//        List<MemberGroupUserRespVO> respVOS = memberGroupMapper.memberGroupUserList(groupId);
//        respVOS= respVOS.stream().peek(memberGroupUserRespVO -> {
//            Long userId = memberGroupUserRespVO.getId();
//            //  填充查询 : 标签
//            memberGroupUserRespVO.setTags(
//                    memberTagRefService.selectByUserIds(Collections.singletonList(userId))
//                            .stream().map(MemberTagRefDTO::getTagName).collect(Collectors.toList())
//            );
//        }).collect(Collectors.toList());
//        return new TableDataInfo(respVOS, PageUtils.getTotal(respVOS));
    }

    @Override
    @Transactional
    public void memberGroupUserUpdate() {
        try {
            lock.lock();
            //所有用户组列表
            List<MemberGroup> memberGroups = memberGroupMapper.selectList(Wrappers.lambdaQuery());
            //所有用户及其特征
            List<MemberGroupUserTraitDetailDTO> userTraitDetailAll = memberUserService.memberAllUserTrait();
            for (MemberGroup memberGroup : memberGroups) {
                Long groupId = memberGroup.getId();
                String ruleInfo = memberGroup.getRuleInfo();
                memberGroupUserAllUpdateHandle(userTraitDetailAll, groupId, ruleInfo);
            }
        } catch (Exception ex) {
            log.error(ex.getMessage());
            ex.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    @Override
    @Transactional
    public void memberGroupUserUpdate(Long groupId) {
        memberGroupUserUpdate(groupId, null);
    }

    @Override
    @Transactional
    public void memberGroupUserUpdate(String groupName) {
        memberGroupUserUpdate(null, groupName);
    }

    private void memberGroupUserUpdate(Long groupId, String groupName) {
        lock.lock();
        try {
            MemberGroup memberGroup = memberGroupMapper.selectOne(Wrappers.<MemberGroup>lambdaQuery()
                    .eq(groupId != null, MemberGroup::getId, groupId)
                    .eq(groupName != null, MemberGroup::getName, groupName)
            );
            //所有用户及其特征
            List<MemberGroupUserTraitDetailDTO> userTraitDetailAll = memberUserService.memberAllUserTrait();
            memberGroupUserAllUpdateHandle(userTraitDetailAll, memberGroup.getId(), memberGroup.getRuleInfo());
        } catch (Exception ex) {
            log.error(ex.getMessage());
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void memberGroupUserUpdateByUserIdSync(Long userId) {
        //触发自动客户分群
        messageProducer.sendMessage(String.valueOf(userId), RabbitMessageTypeEnum.MEMBER_GROUP_UPDATE_BY_USER_ACTION);

    }

    /**
     * 用户支付 ，创建订单，加购物车，更新标签，登录（最后到访） 时候触发
     * @param userId
     */
    @Transactional
    public void memberGroupUserUpdateByUserId(Long userId) {
        try {
            lock.lock();
            //所有人群组
            List<MemberGroup> memberGroups = memberGroupMapper.selectList(Wrappers.lambdaQuery());
            //当前用户所在的组
            List<Long> userInGroupIds = memberGroupMapper.selectGroupIdByUserId(userId);
            //当前用户的特征
            MemberGroupUserTraitDetailDTO userTrait = memberUserService.memberGroupUserTrait(userId).get(0);
            for (MemberGroup memberGroup : memberGroups) {
                Long groupId = memberGroup.getId();
                memberGroupUserUpdateHandle(userTrait, userInGroupIds != null && !userInGroupIds.isEmpty() && userInGroupIds.contains(groupId), groupId, memberGroup.getRuleInfo());
            }
        } catch (Exception ex) {
            log.error(ex.getMessage());
            ex.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 用户组中满足条件的用户更新
     *
     * @param groupId  组id
     * @param ruleInfo 条件
     */

    private void memberGroupUserAllUpdateHandle(List<MemberGroupUserTraitDetailDTO> userTraitDetailAll, Long groupId, String ruleInfo) {
        //特征规则
        Map<String, Object> ruleMap = BeanUtil.beanToMap(JSON.parseObject(ruleInfo));
        //符合特征的用户信息
        List<MemberGroupUserTraitDetailDTO> filter = userTraitDetailAll
                .stream()
                .filter(userTraitDetail -> memberGroupUserUpdateConditions(ruleMap, userTraitDetail))
                .collect(Collectors.toList());
        if (!filter.isEmpty()) {
            //删除原有的组关系
            memberGroupMapper.deleteMemberGroupRefByGroupId(groupId);
            // 添加新的符合条件的组关系
            memberGroupMapper.insertMemberGroupRef(groupId, filter);
            //更新组中人数
            memberGroupMapper.updateById(MemberGroup.builder().id(groupId).userCount((long) filter.size()).build());
        }
    }

    /**
     * 根据用户特征 移出、进入分组
     *
     * @param userTraitDetail
     * @param inGroupNow      groupId当前是否在该用户所在的人群组
     * @param groupId
     * @param ruleInfo
     */
    private void memberGroupUserUpdateHandle(MemberGroupUserTraitDetailDTO userTraitDetail, boolean inGroupNow, Long groupId, String ruleInfo) {
        Long userId = userTraitDetail.getUserId();
        //用户是否符合特征
        boolean haveTrait = memberGroupUserUpdateConditions(BeanUtil.beanToMap(JSON.parseObject(ruleInfo)), userTraitDetail);
        if (inGroupNow && !haveTrait) {
            //原本在组中,但是现在不符合特征，移出该组
            memberGroupMapper.deleteGroupRef(groupId, userId);
            memberGroupMapper.updateGroupMemberCount(groupId, -1);
        }
        if (!inGroupNow && haveTrait) {
            //原本不在组中,但是现在符合特征，加入该组
            memberGroupMapper.addGroupRef(groupId, userId);
            memberGroupMapper.updateGroupMemberCount(groupId, 1);
            // 加入该组 执行运营计划
            memberOperationPlanService.doExecuteAfterAddGroup(groupId, userId);
        }
    }

    /**
     * 是否为最近X天的时间
     *
     * @param day
     * @param lastDay
     * @return
     */
    private boolean isLatelyTime(int day, LocalDateTime lastDay) {
        if (lastDay == null) {
            return false;
        }
        LocalDateTime now = LocalDateTime.now();
        //今天的起点
        LocalDateTime todayStart = LocalDateTime.of(now.getYear(), now.getMonth(), now.getDayOfMonth(), 0, 0);
        //最近的起点
        LocalDateTime latelyStart = todayStart.minusDays(day);
        return latelyStart.equals(lastDay) || latelyStart.isBefore(lastDay);
    }

    /**
     * 特征9，,10中的值判断
     *
     * @param o
     * @param judgmentValue
     * @return
     */
    private boolean conditionMatch(Object o, float judgmentValue) {
        JSONObject jsonObject = JSONObject.from(o);
        String condition = jsonObject.getString("condition");
        float paramValue = jsonObject.getFloat("value");
        switch (Objects.requireNonNull(MemberGroupTraitConditionEnum.get(condition))) {
            case GT:
                return judgmentValue > paramValue;
            case LT:
                return judgmentValue < paramValue;
            case EQ:
                return judgmentValue == paramValue;
            default:
                return false;
        }
    }

    private boolean memberGroupUserUpdateConditions(Map<String, Object> ruleMap, MemberGroupUserTraitDetailDTO userTraitDetail) {
        boolean result = ruleMap.keySet().stream().allMatch(key -> {
            boolean flag = false;
            MemberGroupTraitEnum memberGroupTraitEnum = MemberGroupTraitEnum.get(key);
            //最近xx天
            LocalDateTime lastBuyTime = userTraitDetail.getLastBuyTime();
            LocalDateTime lastOrderTime = userTraitDetail.getLastOrderTime();
            LocalDateTime lastCarTime = userTraitDetail.getLastCarTime();
            LocalDateTime lastVisitTime = userTraitDetail.getLastVisitTime();
            Object o = ruleMap.get(key);
            switch (memberGroupTraitEnum) {
                case HAVE_BUY:
                    flag = isLatelyTime((Integer) o, lastBuyTime);
                    break;
                case NO_BUY:
                    flag = !isLatelyTime((Integer) o, lastBuyTime);
                    break;
                case HAVE_ORDER:
                    flag = isLatelyTime((Integer) o, lastOrderTime);
                    break;
                case NO_ORDER:
                    flag = !isLatelyTime((Integer) o, lastOrderTime);
                    break;
                case HAVE_ADD_CAR:
                    flag = isLatelyTime((Integer) o, lastCarTime);
                    break;
                case NO_ADD_CAR:
                    flag = !isLatelyTime((Integer) o, lastCarTime);
                    break;
                case HAVE_INTERVIEW:
                    flag = isLatelyTime((Integer) o, lastVisitTime);
                    break;
                case NO_INTERVIEW:
                    flag = !isLatelyTime((Integer) o, lastVisitTime);
                    break;
                case BUY_COUNT:
                    flag = conditionMatch(o, userTraitDetail.getBuyCount() == null ? 0 : userTraitDetail.getBuyCount());
                    break;
                case BUY_AMOUNT:
                    flag = conditionMatch(o, userTraitDetail.getBuyAmount() == null ? 0 : userTraitDetail.getBuyAmount());
                    break;
                case TAG:
                    JSONArray jsonArray = JSONArray.of(o).getJSONArray(0);
                    List<Long> tagConfig = jsonArray.toList(MemberTag.class).stream().map(MemberTag::getId).collect(Collectors.toList());
                    List<Long> userTags = userTraitDetail.getTags();
                    // 求交集
                    tagConfig.retainAll(userTags);
                    flag = !tagConfig.isEmpty();
                    break;
            }
            return flag;
        });
        log.info("--------用户特征：{}, 规则：{} ,是否符合：{}-----------------",
                JSONObject.toJSONString(userTraitDetail, JSONWriter.Feature.WriteNulls), ruleMap, result);
        return result;
    }


}
